package graph.editor;


import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTextField;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import automaton.TypeState;
import exception.FormatSaveFileException;
import graph.editor.enhanced.EdgeModified;
import graph.editor.enhanced.VertexModified;
import graph.util.Shapes;

/**
 * @opt nodefillcolor green
 * @opt attributes
 * @opt operations
 * @depend - - - graph.util.Shapes
 * @depend - - - exception.FormatSaveFileException
 * @depend - - - automaton.TypeState
 */

public class DataReader {
	private 	List<EdgeModified> 		edges;
	private 	List<VertexModified>	vertices;
	private		File					xmlFile;
	
	public DataReader(File xmlFile){
		this.vertices			= new ArrayList<VertexModified>();
		this.edges 				= new ArrayList<EdgeModified>();
		this.xmlFile			= xmlFile;
	}
	
	public void load(){
		this.vertices			= new ArrayList<VertexModified>();
		this.edges 				= new ArrayList<EdgeModified>();
		try{
			DocumentBuilderFactory 	factory 		= DocumentBuilderFactory.newInstance();
			DocumentBuilder 		builder 		= factory.newDocumentBuilder();
			Document 				document 		= builder.parse(xmlFile);
			Element 				root 			= document.getDocumentElement();
			NodeList				stateList		= root.getElementsByTagName("state");
			NodeList				transitionList	= root.getElementsByTagName("transition");
			for(int i = 0; i < stateList.getLength(); i++){
				stateNodeReader(stateList.item(i));
			}
			for(int i = 0; i < transitionList.getLength(); i++){
				transitionNodeReader(transitionList.item(i));
			}
		}catch(ParserConfigurationException e){
			System.err.println("Erreur de configuration du parseur DOM");
			System.err.println("lors de l'appel à fabrique.newDocumentBuilder();");
			e.printStackTrace();
		}catch(SAXException e){
			System.err.println("Erreur lors du parsing du document");
			System.err.println("lors de l'appel à construteur.parse(xml)");
			e.printStackTrace();
		}catch(IOException e){
			System.err.println("Erreur d'entrée/sortie");
			System.err.println("lors de l'appel à construteur.parse(xml)");
			e.printStackTrace();
		} catch (FormatSaveFileException e) {
			e.printStackTrace();
		}
	}
	
	public List<EdgeModified> getEdges(){
		return this.edges;
	}
	
	public List<VertexModified> getVertices(){		
		return this.vertices;
	}

	private TypeState getTypeState(String source, String terminal) throws FormatSaveFileException{
		TypeState typeState = null;
		if(source.equals("true") && terminal.equals("false"))
			typeState = TypeState.INITIAL;
		else if(source.equals("true") && terminal.equals("true"))
			typeState = TypeState.INITIAL_AND_FINAL;
		else if(source.equals("false") && terminal.equals("true"))
			typeState = TypeState.FINAL;
		else if(source.equals("false") && terminal.equals("false"))
			typeState = TypeState.INTERMEDIATE;
		else
			throw new FormatSaveFileException();
		return typeState;
	}

	private void stateNodeReader(Node node) throws FormatSaveFileException{
		Element 	state 			= (Element)node;
		NodeList 	stateIdList		= state.getElementsByTagName("id");
		NodeList	positionXList	= state.getElementsByTagName("positionX");
		NodeList	positionYList	= state.getElementsByTagName("positionY");
		NodeList	isInitialList	= state.getElementsByTagName("isInitial");
		NodeList	isFinalList		= state.getElementsByTagName("isFinal");
		if((stateIdList.getLength() != 1) || (positionXList.getLength() != 1) || (positionYList.getLength() != 1) || (isInitialList.getLength() != 1) || (isFinalList.getLength() != 1))
			throw new FormatSaveFileException();
		double x 			= Double.parseDouble(positionXList.item(0).getTextContent());
		double y 			= Double.parseDouble(positionYList.item(0).getTextContent());
		int id 				= Integer.parseInt(stateIdList.item(0).getTextContent());
		TypeState typeState = getTypeState(isInitialList.item(0).getTextContent(), isFinalList.item(0).getTextContent());
		VertexModified v = createVertex(x, y, id, typeState);
		vertices.add(id, v) ;
	}
	
	private void transitionNodeReader(Node node) throws FormatSaveFileException{
		Element 	transition		= (Element)node;
		NodeList	transitionId	= transition.getElementsByTagName("id");
		NodeList	labelList		= transition.getElementsByTagName("label");
		NodeList	sourceList		= transition.getElementsByTagName("source");
		NodeList	targetList		= transition.getElementsByTagName("target");
		NodeList	joinPointList	= transition.getElementsByTagName("point");
		if((transitionId.getLength() < 1) || (labelList.getLength() != 1) || (sourceList.getLength() != 1) || (targetList.getLength() != 1))
			throw new FormatSaveFileException();
		String label 		= labelList.item(0).getTextContent();
		VertexModified v1 	= vertices.get(Integer.parseInt(sourceList.item(0).getTextContent()));
		VertexModified v2 	= vertices.get(Integer.parseInt(targetList.item(0).getTextContent()));
		EdgeModified edge 	= new EdgeModified(v1, v2);
		addEdgeLabel(edge,label);
		if(joinPointList.getLength() > 0){
			for(int i = 0; i < joinPointList.getLength(); i++){
				Element 	point 			= (Element)joinPointList.item(i);
				NodeList	positionXList	= point.getElementsByTagName("positionX");
				NodeList	positionYList	= point.getElementsByTagName("positionY");
				if((positionXList.getLength() != 1) || (positionYList.getLength() != 1))
					throw new FormatSaveFileException();
				double x = Double.parseDouble(positionXList.item(0).getTextContent());
				double y = Double.parseDouble(positionYList.item(0).getTextContent());
				edge.addJointPoint(x,y);
			}
		}
		edges.add(edge);
	}

	private void addEdgeLabel(final Edge edge, String label) {
		final JTextField textField = new JTextField(label);
		textField.setSize(100, 20);
		textField.setLocation(edge.labelPosition());
		edge.textField = textField;
	}
	

	private VertexModified createVertex(double x, double y, int id, TypeState typeState) {
		RectangularShape 	rs 		=  null;
		switch (typeState) {
		case INITIAL_AND_FINAL:
			rs = (RectangularShape) new Rectangle2D.Double(0, 0, 15, 15);
			break;
		case INITIAL:
			rs = (RectangularShape) new Rectangle2D.Double(0, 0, 10, 10);
			break;
		case FINAL:
			rs = (RectangularShape) new Rectangle2D.Double(0, 0, 20, 20);
			break;
		case INTERMEDIATE:
		default:
			rs = (RectangularShape) new Ellipse2D.Double(0, 0, 10, 10);
			break;
		}
		Shapes.moveShape(rs, (int)x, (int)y);
		VertexModified v = new VertexModified(rs, Integer.toString(id), typeState);
		return v;
	}
}
